package com.lagou.concurrent.demo;

public class ReadWriteLock {
    // 读取的线程数
    private int readingReaders = 0;
    // 等待写入的线程数
    private int waitingWriters = 0;
    // 正在写的线程数
    private int writingWriters = 0;
    // 是否偏向写
    private boolean preferWriter = true;

    /**
     * 对于读操作：
     * 1. 如果有正在写入的writer，则当前线程等待writer写入完成
     * 2. 如果没有正在写入的writer，但是有正在等待写入的writer，同时偏向写操作
     *    则当前线程等待writer写入完成
     * @throws InterruptedException
     */
    public synchronized void readLock() throws InterruptedException {
        while (writingWriters > 0 || (preferWriter && waitingWriters > 0)) {
            // 当前线程等待
            wait();
        }
        readingReaders++;
    }

    public synchronized void readUnlock() {
        readingReaders--;
        preferWriter = true;
        // 唤醒在当前对象上等待的其他线程
        notifyAll();
    }

    public synchronized void writeLock() throws InterruptedException {
        waitingWriters++;
        try {
            // 如果有正在读取的线程，或者有正在写入的线程，则当前线程等待被唤醒
            while (readingReaders > 0 || writingWriters > 0) {
                wait();
            }
        } finally {
            waitingWriters--;
        }
        writingWriters++;
    }

    public synchronized void writeUnlock() {
        writingWriters--;
        preferWriter = false;
        // 当前线程写入完成，唤醒其他等待的线程进行读写操作
        notifyAll();
    }

}